package engine.game.level;

import engine.game.level.Level.LevelResize;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import engine.game.level.tiles.Tile;
import engine.resource.Resources;
import util.Logger;

/**
 * A class for storing the map for a level
 *
 * @author Nathan T
 *
 */
public class LevelMap {

    private static final Logger logger = Logger.getDefaultLogger();

    // State Variables
    private Tile[][] tiles;
    private int width;
    private int height;
    private String filePath;

    /**
     * Standard Constructor
     *
     * @param tiles    the tiles that form this level map
     * @param filePath the File Path to the data file that the LevelMap
     *                 represents
     */
    public LevelMap(Tile[][] tiles, String filePath) {
        this.tiles = tiles;
        this.width = tiles.length;
        this.height = tiles[0].length;
        this.filePath = filePath;
    }

    /**
     * Width getter
     *
     * @return Returns the width of the LevelMap
     */
    public int width() {
        return width;
    }

    /**
     * Height getter
     *
     * @return Returns the height of the LevelMap
     */
    public int height() {
        return height;
    }

    /**
     * Accesses the Tile at a specific location
     *
     * @param x The x coordinate of the desired Tile
     * @param y The y coordinate of the desired Tile
     *
     * @return Returns the tile at the specified location
     */
    public Tile tileAt(int x, int y) {
        if (x >= width || x < 0 || y >= height || y < 0) {
            return Resources.getTile("VOID");
        }
        return tiles[x][y];
    }

    public void setTile(int x, int y, Tile tile) {
        if (x >= width || x < 0 || y >= height || y < 0) {
            return;
        }
        tiles[x][y] = tile;
    }

    public String filePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public String[] getContent() {
        ArrayList<String> cont = new ArrayList<>();

        Map<Tile, Integer> key = new HashMap<>();
        ArrayList<String> lines = new ArrayList<>();
        int nextId = 0;

        for (int y = 0; y < tiles[0].length; y++) {
            String line = "line" + y + " =";
            for (int x = 0; x < tiles.length; x++) {
                Tile nextTile = tileAt(x, y);
                if (!key.containsKey(nextTile)) {
                    key.put(nextTile, nextId);
                    nextId++;
                }
                line += "\t" + key.get(nextTile);
            }
            lines.add(line);
        }

        cont.add("KEY");
        cont.add("{");
        for (Tile tile : key.keySet()) {
            cont.add(key.get(tile) + " = " + tile.name());
        }
        cont.add("}");

        cont.add("MAP");
        cont.add("{");
        for (String line : lines) {
            cont.add(line);
        }
        cont.add("}");

        String[] result = new String[cont.size()];
        for (int i = 0; i < cont.size(); i++) {
            result[i] = cont.get(i);
        }

        return result;
    }

    public void save() {
        try {
            File outputFile = new File(filePath);
            try (FileWriter fw = new FileWriter(outputFile);
                    PrintWriter pw = new PrintWriter(fw)) {

                String[] content = getContent();
                for (String line : content) {
                    pw.println(line);
                }

            }
        }
        catch (IOException e) {
            logger.log(e);
        }
    }

    public void applyResize(LevelResize resize) {
        int oldWidth = this.width;
        int oldHeight = this.height;

        this.width = oldWidth + resize.getAddLeft() + resize.getAddRight() - resize.getRemLeft() - resize.getRemRight();
        this.height = oldHeight + resize.getAddTop() + resize.getAddBot() - resize.getRemTop() - resize.getRemBot();

        Tile[][] newTiles = new Tile[width][height];

        for (int i = 0; i < newTiles.length; i++) {
            for (int j = 0; j < newTiles[0].length; j++) {
                int oldI = i - resize.getAddLeft();
                int oldJ = j - resize.getAddTop();
                if (oldI < 0 || oldI >= oldWidth) {
                    newTiles[i][j] = Resources.getTile("VOID");
                }
                else if (oldJ < 0 || oldJ >= oldHeight) {
                    newTiles[i][j] = Resources.getTile("VOID");
                }
                else {
                    newTiles[i][j] = tiles[oldI][oldJ];
                }
            }
        }

        tiles = newTiles;
    }

}
